﻿﻿/* **********************************************************************************
 * Copyright (c) 2011 John Hughes
 *
 * j9Script is licenced under the Microsoft Reciprocal License (Ms-RL).
 *
 * Project Website: http://j9Script.codeplex.com/
 * **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

namespace J9Script
{

    /// <summary>
    /// This type of exception is thown by the Expression Evaluator.
    /// </summary>
    [Serializable]
    public class ScriptEvaluatorException : Exception
    {
        public ScriptPosition Position = ScriptPosition.Empty;
        public string ScriptSnippet = "";

        /// <summary>Initializes a new instance of the ScriptEvaluatorException class with a specified error message.</summary>
        /// <param name="message">The error message that explains the reason for the exception.</param>
        public ScriptEvaluatorException(string message)
            : base(message)
        {
        }

        public ScriptEvaluatorException(ScriptObjectInvokeResult result, string objectName, string memberName, ScriptPosition position, string scriptSnippet)
            : base(scriptObjectInvokeResultToMessage(result, objectName, memberName, new IScriptObject[] { }))
        {
            Position = position;
            ScriptSnippet = scriptSnippet;
        }
        public ScriptEvaluatorException(ScriptObjectInvokeResult result, string objectName, string memberName, IScriptObject[] methodArgs, ScriptPosition position, string scriptSnippet)
            : base(scriptObjectInvokeResultToMessage(result, objectName, memberName, methodArgs))
        {
            Position = position;
            ScriptSnippet = scriptSnippet;
        }

        // This is so the object can be deserialized -- since we have [Serializable] on the class
        protected ScriptEvaluatorException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context) { }

        /// <summary>
        /// Initializes a new instance of the ScriptEvaluatorException class with a specified error message and a reference to the inner exception that is the cause of this exception.
        /// </summary>
        /// <param name="message">The error message that explains the reason for the exception.</param>
        /// <param name="innerException">The exception that is the cause of the current exception. If the innerException parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception.</param>
        public ScriptEvaluatorException(string message, Exception innerException)
            : base(message, innerException)
        {
        }

        public ScriptEvaluatorException(string message, ScriptPosition position, string scriptSnippet)
            : this(message, position, scriptSnippet, null)
        {
            Position = position;
            ScriptSnippet = scriptSnippet;
        }

        public ScriptEvaluatorException(string message, ScriptPosition position, string scriptSnippet, Exception innerException)
            : base(message, innerException)
        {
            Position = position;
            ScriptSnippet = scriptSnippet;
        }

		private static string scriptObjectInvokeResultToMessage(ScriptObjectInvokeResult result, string objectName, string memberName, IScriptObject[] methodArgs)
        {
            switch (result)
            {
                case ScriptObjectInvokeResult.InvalidType:
                    return string.Format("The type for '{0}.{1}' has the wrong type.  Properties must be of type IScriptObject and Methods must be void or IScriptObject.", objectName, memberName);
                case ScriptObjectInvokeResult.IsReadOnly:
                    return string.Format("The property {0}.{1} can not be used in this context because it lacks a set accessor.", objectName, memberName);
                case ScriptObjectInvokeResult.IsWriteOnly:
                    return string.Format("The property {0}.{1} can not be used in this context because it lacks a get accessor.", objectName, memberName);
                case ScriptObjectInvokeResult.MissingScriptMethodAttribute:
                    return string.Format("'{0}' has a method definition for '{1}' but it does not have an [ScriptObjectMethodAttribute] attribute.", objectName, memberName);
                case ScriptObjectInvokeResult.MissingScriptPropertyAttribute:
                    return string.Format("'{0}' has a property definition for '{1}' but it does not have an [ScriptObjectPropertyAttribute] attribute.", objectName, memberName);
                case ScriptObjectInvokeResult.UndefinedMember:
                    return string.Format("'{0}' does not contain a member definition for '{1}'.", objectName, memberName);
                case ScriptObjectInvokeResult.WrongNumberOfArguments:
                    return string.Format("No overload for method '{0}.{1}' takes '{2}' arguments.", objectName, memberName, methodArgs.Length);
                default:
                    return string.Format("An unknown ScriptObjectInvokeResult was returned from '{0}.{1}'.", objectName, memberName);
            }
        }

    }
}
